#pragma once

#include <map>
#include <iostream>
#include <string>
#include <cassert>

namespace MemMgr
{

class MemoryTracker
{

public:

	~MemoryTracker();

	void RegisterAlloc(const void * const iPtr, const size_t iSize, const char* iFilename, const char* iFunctionName, const unsigned int iRow, std::string iCategory);
	void UnregisterAlloc(const void * const iPtr, const size_t iSize);
	void UnregisterAlloc(const void * const iPtr);

	static MemoryTracker& GetSingleton();
	static MemoryTracker* GetSingletonPtr();

private:

	explicit MemoryTracker(std::ostream& oStream = std::clog);

	void LogError(const void* const iPtr);
	void LogError(const void * const iPtr, const size_t iSize);
	void LogLeaks();

private:

	struct AllocationInfo
	{
		AllocationInfo(){}
		AllocationInfo(size_t iSize, const char* iFilename, const char* iFunctionName, const unsigned int iRow, std::string iCategory)
			: size(iSize), filename(iFilename), functionName(iFunctionName), line(iRow), category(iCategory) {}
		size_t size;
		const char* filename;
		const char* functionName;
		unsigned int line;
		std::string category;
	};

	typedef std::map<const void *, AllocationInfo> AllocationInfoMap;
	
	size_t mAllocatedMemory;
	AllocationInfoMap mAllocationMap;
	std::ostream& mOutput;
};

}